package com.lgj.rocketmq.code;

import com.lgj.rocketmq.annotation.EnableMqTransaction;
import com.lgj.rocketmq.message.RocketMessage;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: guangjie.liao
 * @Date: 2023/9/05 22:15
 * @Description: 本地事务执行
 */
@Component
public class ProducerTransactionFactory implements ApplicationContextAware, SmartInitializingSingleton {
    public static Map<String, Method> methodMap = new HashMap<>();

    public static Map<String, Object> beansMap = new HashMap<>();
    private ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterSingletonsInstantiated() {
        Map<String, Object> transactionBeanMap = applicationContext.getBeansWithAnnotation(EnableMqTransaction.class);
        if (!transactionBeanMap.isEmpty()){
            transactionBeanMap.forEach((beanName,bean)->{
                Method[] declaredMethods = AopProxyUtils.ultimateTargetClass(bean).getDeclaredMethods();
                for (Method method : declaredMethods) {
                    if (method.isAnnotationPresent(MqTransaction.class)) {
                        MqTransaction localTransaction = method.getAnnotation(MqTransaction.class);
                        methodMap.put(localTransaction.topic(), method);
                        beansMap.put(localTransaction.topic(),bean);
                    }
                }
            });
        }
    }

    /**
     * 执行本地事务方法
     * @param message RocketMessage
     * @return void
     * @author guangjie.liao
     * @since 2023/9/20 22:32
     */
    public void invokeMethod(RocketMessage message){
        String topic = message.getTopic();
        Method method = methodMap.get(topic);
        Object bean = beansMap.get(topic);
        ReflectionUtils.invokeMethod(method,bean,message);
    }

}
